#include <zephyr.h>
#include <sys/printk.h>
#include <shell/shell.h>
#include <shell/shell_uart.h>
#include <logging/log.h>

#include <version.h>
#include <stdlib.h>
#include <gpio.h>
#include <board.h>
#include <pwm.h>
#include <led.h>
#include "nrf52.h"
#include "nrf.h"
#include "test.h"
#include <sensor.h>

#include <adc.h>
#include <hal/nrf_saadc.h>

#define ADC_DEVICE_NAME		DT_ADC_0_NAME
#define ADC_RESOLUTION		10
#define ADC_GAIN		ADC_GAIN_1_6
#define ADC_REFERENCE		ADC_REF_INTERNAL
#define ADC_ACQUISITION_TIME	ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10)
#define ADC_1ST_CHANNEL_ID	0
#define ADC_1ST_CHANNEL_INPUT	NRF_SAADC_INPUT_AIN1

#define BUFFER_SIZE  1
static s16_t m_sample_buffer[BUFFER_SIZE];

static const struct adc_channel_cfg m_1st_channel_cfg = {
	.gain             = ADC_GAIN,
	.reference        = ADC_REFERENCE,
	.acquisition_time = ADC_ACQUISITION_TIME,
	.channel_id       = ADC_1ST_CHANNEL_ID,
#if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
	.input_positive   = ADC_1ST_CHANNEL_INPUT,
#endif
};

static struct device *adc_dev;

static struct device *init_adc(void)
{
	int ret;
	struct device *adc_dev = device_get_binding(ADC_DEVICE_NAME);
	if(adc_dev == NULL){
		printk("Cannot get ADC device");
	}

	ret = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
	if(ret != 0){
		printk("Setting up of the first channel failed with code %d", ret);
	}

	(void)memset(m_sample_buffer, 0, sizeof(m_sample_buffer));

	return adc_dev;
}

LOG_MODULE_REGISTER(app);

static int cmd_dht(const struct shell *shell, size_t argc, char **argv)
{
	struct sensor_value temp, humidity;
	struct device *dev = device_get_binding("DHT11"); //根据Device name获取驱动
	shell_fprintf(shell, SHELL_NORMAL,"dev %p name %s\n", dev, dev->config->name);
	sensor_sample_fetch(dev);								  //从dh11读取数据
	sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); //读取温度
	sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity); //读取湿度

	shell_fprintf(shell, SHELL_NORMAL,"temp: %d.%06d; humidity: %d.%06d\n",
		   temp.val1, temp.val2, humidity.val1, humidity.val2);
	return 0;
}

static int cmd_adc(const struct shell *shell, size_t argc, char **argv)
{
	adc_dev = init_adc();
	if(adc_dev){
		const struct adc_sequence sequence = {
			.channels    = BIT(ADC_1ST_CHANNEL_ID),
			.buffer      = m_sample_buffer,
			.buffer_size = sizeof(m_sample_buffer),
			.resolution  = ADC_RESOLUTION,
		};

		int ret;
		ret = adc_read(adc_dev, &sequence);
		if(ret == 0){
			shell_fprintf(shell, SHELL_NORMAL,"Read bat %d\n", m_sample_buffer[0]);
		}
	}
}

static void swo_cfg_enable()
{
	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
	*((volatile unsigned *)(ITM_BASE + 0x400F0)) = 0x00000002;										   /* "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO NRZ, 1: SWO Manchester encoding) */
	*((volatile unsigned *)(ITM_BASE + 0x40010)) = 499;												   /* "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output */
	*((volatile unsigned *)(ITM_BASE + 0x00FB0)) = 0xC5ACCE55;										   /* ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC */
	ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk; /* ITM Trace Control Register */
	ITM->TPR = ITM_TPR_PRIVMASK_Msk;																   /* ITM Trace Privilege Register */
	ITM->TER = 1;																					   /* ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. */
	*((volatile unsigned *)(ITM_BASE + 0x01000)) = 0x400003FE;										   /* DWT_CTRL */
	*((volatile unsigned *)(ITM_BASE + 0x40304)) = 0x00000100;										   /* Formatter and Flush Control Register */

	NRF_CLOCK->TRACECONFIG = (CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos) | 0x3;
	NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
}

static int (*__printk_out)(int);

static int semi_console_out(int character)
{
	if(__printk_out)
		__printk_out(character);
	return (int)ITM_SendChar((uint32_t)character);
}

static void cmd_semihost(const struct shell *shell, size_t argc, char **argv)
{
	swo_cfg_enable();
	__printk_out = __printk_get_hook();
	__printk_hook_install(semi_console_out);
	__stdout_hook_install(semi_console_out);
}

static void cmd_version(const struct shell *shell, size_t argc, char **argv)
{
	ARG_UNUSED(argc);
	ARG_UNUSED(argv);

	shell_fprintf(shell, SHELL_NORMAL,"Zephyr version %s\n", KERNEL_VERSION_STRING);
}

static void cmd_clk(const struct shell *shell, size_t argc, char **argv)
{
	ARG_UNUSED(argc);
	ARG_UNUSED(argv);

	shell_fprintf(shell, SHELL_NORMAL,"Zephyr CLK %llu\n", (u64_t)sys_clock_hw_cycles_per_sec);
	shell_fprintf(shell, SHELL_NORMAL,"Zephyr trick %u\n", k_cycle_get_32());
	k_sleep(100);
	shell_fprintf(shell, SHELL_NORMAL,"Zephyr trick now %u\n", k_cycle_get_32());
}

static void cmd_demo_ping(const struct shell *shell, size_t argc, char **argv)
{
	ARG_UNUSED(argc);
	ARG_UNUSED(argv);

	shell_fprintf(shell, SHELL_NORMAL, "pong\r\n");
}

static void cmd_demo_params(const struct shell *shell, size_t argc, char **argv)
{
	int cnt;

	shell_fprintf(shell, SHELL_NORMAL, "argc = %d\r\n", argc);
	for (cnt = 0; cnt < argc; cnt++) {
		shell_fprintf(shell, SHELL_NORMAL,
				"  argv[%d] = %s\r\n", cnt, argv[cnt]);
	}
}

SHELL_CREATE_STATIC_SUBCMD_SET(sub_demo)
{
	/* Alphabetically sorted. */
	SHELL_CMD(params, NULL, "Print params command.", cmd_demo_params),
	SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
	SHELL_SUBCMD_SET_END /* Array terminated. */
};

SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
SHELL_CMD_REGISTER(ver, NULL,"Show kernel version", cmd_version);
SHELL_CMD_REGISTER(clk, NULL, "get clk", cmd_clk);
SHELL_CMD_REGISTER(semi, NULL, "switch semi",  cmd_semihost);
SHELL_CMD_REGISTER(dht, NULL, "get dht", cmd_dht);
SHELL_CMD_REGISTER(adc, NULL, "get bat", cmd_adc);


void main(void)
{
	//net_test_init();
	//bt_test_init();
	//hr_init();
	float x = 1.35;
	printf("Frank printf %f\n", x);

	esp_init();
}
